package com.example.hello;

import com.example.hello.POJO.*;
import com.example.hello.views.CreateUserView;
import com.example.hello.views.ManageUsersView;
import com.example.hello.views.StaticView;
import com.example.hello.views.Wireframe1;
import com.example.hello.views.access_control.LogIn;
import com.example.hello.views.access_control.LogOut;
import com.example.hello.views.access_control.SignUp;
import com.example.hello.views.assignments.Assignment;
import com.example.hello.views.assignments.Assignments;
import com.example.hello.views.assignments.EditAssignment;
import com.example.hello.views.badges.Badge;
import com.example.hello.views.badges.Badges;
import com.example.hello.views.organizations.EditOrg;
import com.example.hello.views.organizations.Organization;
import com.example.hello.views.organizations.Organizations;
import com.example.hello.views.submissions.Submissions;
import com.example.hello.views.tracks.Track;
import com.example.hello.views.tracks.Tracks;
import com.example.hello.views.users.EditUser;
import com.example.hello.views.users.User;
import com.example.hello.views.users.Users;
import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.annotations.Theme;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.util.*;

@PreserveOnRefresh
@Theme("helloVG")
@SuppressWarnings("serial")
public class HelloUI extends UI {

    VerticalLayout body = new VerticalLayout();
    public static int SIZE = 1200;

    private boolean logInOutFlag = false;

    private UserPOJO user = new UserPOJO("login", null);
    private UserPOJO selectedUser;
    private OrganizationPOJO selectedOrg;
    private TrackPOJO selectedTrack;

    public static String resourceLocation = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();

    @Override
    protected void init(VaadinRequest request) {
        initNavigatorViews();

        getCurrent().getSession().setAttribute("isLoggedIn", false);
        getCurrent().getSession().setAttribute("previousView", "");
        getCurrent().getSession().setAttribute("currentUser", "");
        getCurrent().getSession().setAttribute("currentOrg", "");
        getCurrent().getSession().setAttribute("currentRow", "");

        setContent(new StaticView(body));
//        FileMonitor monitor = new FileMonitor();
    }

    private void initNavigatorViews() {
        Navigator navigator = new Navigator(this, body);

        navigator.addViewChangeListener(new ViewChangeListener() {
            @Override
            public boolean beforeViewChange(ViewChangeEvent event) {
                return true;
            }

            @Override
            public void afterViewChange(ViewChangeEvent event) {
                if (logInOutFlag) {
                    setContent(new StaticView(body));
                    logInOutFlag = false;
                }
            }
        });
        navigator.addView(Wireframe1.NAME, Wireframe1.class);

        navigator.addView(Organizations.NAME, Organizations.class);
        navigator.addView(Tracks.NAME, Tracks.class);
        navigator.addView(Submissions.NAME, Submissions.class);
        navigator.addView(Badges.NAME, Badges.class);
        initOrgViews();
        initTrackViews();
        initSubmissionViews();
        initBadgeViews();
        
        navigator.addView(Assignments.NAME, Assignments.class);
        initAssignmentViews();

        navigator.addView(LogIn.NAME, LogIn.class);
        navigator.addView(LogOut.NAME, LogOut.class);
        navigator.addView(SignUp.NAME, SignUp.class);

        navigator.addView(EditAssignment.NAME, EditAssignment.class);

        navigator.addView(CreateUserView.NAME, CreateUserView.class);
        navigator.addView(ManageUsersView.NAME, ManageUsersView.class);

        navigator.addView(Users.NAME, Users.class);
        initUserViews();

        navigator.addView(EditUser.NAME, EditUser.class);
        navigator.addView(EditOrg.NAME, EditOrg.class);
    }

    private void initOrgViews() {
        Set<OrganizationPOJO> orgs = Organizations.GETOrganizations("");
        for (OrganizationPOJO org : orgs) {
            Organization orgView = new Organization(Organizations.NAME + "/" + org.getEncodedName(), org);
            getUI().getNavigator().addView(orgView.NAME, orgView);
        }
    }

    private void initTrackViews() {
        Set<TrackPOJO> tracks = Tracks.GETTracks("");
        for (TrackPOJO track : tracks) {
            Track trackView = new Track(Tracks.NAME + "/" + track.getEncodedName(), track);
            getUI().getNavigator().addView(trackView.NAME, trackView);
        }
    }
    
    private void initSubmissionViews() {
    }

    private void initBadgeViews() {
        Set<BadgePOJO> badges = Badges.GETBadges("");
        for (BadgePOJO badge : badges) {
            Badge badgeView = new Badge(Badges.NAME + "/" + badge.getEncodedName(), badge);
            getUI().getNavigator().addView(badgeView.NAME, badgeView);
        }
    }

    private void initAssignmentViews() {
        List<AssignmentPOJO> assignments = Assignments.GETAssignments("");
        for (AssignmentPOJO assignment : assignments) {
            Assignment assignmentView = new Assignment(Assignments.NAME + "/" + assignment.getEncodedName(), assignment);
            getUI().getNavigator().addView(assignmentView.NAME, assignmentView);
        }
    }

    private void initUserViews() {
        Set<UserPOJO> users = Users.GETUsers("");
        for (UserPOJO user : users) {
            User profile = new User(Users.NAME + "/" + user.getUserName(), false, user, null);
            getUI().getNavigator().addView(profile.NAME, profile);
        }
    }

    public static List<HashMap<String, String>> populateTable(Set<? extends POJO> data) {
        List<HashMap<String, String>> rows = new ArrayList<>();

        for (POJO pojo : data) {
            LinkedHashMap<String, Object> map = pojo.toLinkedHashMap();
            HashMap<String, String> row = new HashMap<>();
            try {
                // each element of this for loop is a key-value pair for the user
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    String str = "";
                    if (entry.getValue() instanceof ArrayList) {
                        // if the value is an array, convert it to a string
                        ArrayList objs = (ArrayList) entry.getValue();
                        if (!objs.isEmpty()) {
                            for (int i = 0; i < objs.size() - 1; i++) {
                                str += objs.get(i).toString() + ", ";
                            }
                            str += objs.get(objs.size() - 1).toString();
                        }
                    } else {
                        str = entry.getValue().toString();
                    }
                    // add the element value to the row
                    row.put(entry.getKey(), str);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!row.isEmpty()) rows.add(row); // don't bother adding if there's nothing to add
        }

        return rows;
    }

    public boolean getLogInOutFlag() {
        return logInOutFlag;
    }

    public void setLogInOutFlag(boolean logInOutFlag) {
        this.logInOutFlag = logInOutFlag;
    }

    public UserPOJO getUser() {
        return user;
    }

    public void setUser(UserPOJO user) {
        this.user = user;
    }

    public UserPOJO getSelectedUser() {
        return selectedUser;
    }

    public void setSelectedUser(UserPOJO selectedUser) {
        this.selectedUser = selectedUser;
    }

    public OrganizationPOJO getSelectedOrg() {
        return selectedOrg;
    }

    public void setSelectedOrg(OrganizationPOJO selectedOrg) {
        this.selectedOrg = selectedOrg;
    }

    public TrackPOJO getSelectedTrack() {
        return selectedTrack;
    }

    public void setSelectedTrack(TrackPOJO selectedTrack) {
        this.selectedTrack = selectedTrack;
    }

}